package conexao;

import java.io.*;
import java.util.Timer;
import java.util.TimerTask;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.SocketConnection;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.file.FileConnection;
import javax.microedition.lcdui.*;
import recados.Recados;

public class Http extends Canvas implements Runnable, CommandListener {

    //Estado conexao
    public static final int NO_INIT = 0;
    public static final int WORKING = 1;
    public static final int STOPPED = 2;
    public static final int FAILED = 3;
    public static final int DONE = 4;
    private int estado;
    //
    private boolean caixaSaida = false;
    // GUI
    private final Command cmdCancelar;
    private final Command cmdVoltar;
    private String mensagem = "Processando";
    private int dots = 1;
    //
    private HttpData dados;
    private HttpListener listener;
    private boolean requestStop;
    //Conexao
    private StreamConnection conn_ref;
    private DataInputStream in;
    private DataOutputStream out;

    //TODO Estado no http
    public Http(String titulo) {
        setTitle(titulo);
        cmdCancelar = new Command("Cancelar", Command.STOP, 0);
        cmdVoltar = new Command("Voltar", Command.BACK, 1);
        addCommand(cmdCancelar);
        setCommandListener(this);
    }

    protected void paint(Graphics g) {
        g.setColor(0);
        g.fillRect(0, 0, getWidth(), getHeight());

        g.setColor(0xffffff);

        int msg_width = g.getFont().stringWidth(mensagem);

        int centro_horizontal = (getWidth() - msg_width) / 2;
        int centro_vertical = (getHeight() - g.getFont().getHeight()) / 2;

        g.drawString(mensagem, centro_horizontal, centro_vertical, 0);

        String pontos = null;

        if (dots == 1) {
            pontos = ".";
        } else if (dots == 2) {
            pontos = "..";
        } else if (dots == 3) {
            pontos = "...";
        }

        g.drawString(pontos, centro_horizontal, centro_vertical + g.getFont().getHeight() + 1, 0);

        dots++;

        if (dots > 3) {
            dots = 1;
        }
    }

    public void commandAction(Command c, Displayable d) {
        if (c == cmdCancelar) {
            cancela();
        }
    }

    public void setMensagem(String mensagem) {
        this.mensagem = mensagem;
    }

    /**
     * ***************************Conexao**********
     */
    private void runSocket() {
        try {
            String adcomule = "socket://antoniodiego.comule.com:80";

            SocketConnection conn = (SocketConnection) Connector.open(adcomule);
            conn_ref = conn;

            if (requestStop) {
                return;
            }

            in = conn.openDataInputStream();
            out = conn.openDataOutputStream();

            if (requestStop) {
                return;
            }

            out.write(("POST /recados_app/" + dados.getPagina() + " HTTP/1.1\r\n").getBytes());
            out.write("Host: antoniodiego.comule.com:80\r\n".getBytes());
            out.write("User-Agent: Recados/3.5.3 (TheAntonioDiego)\r\n".getBytes());
            out.write("Connection: close\r\n".getBytes());
            out.write("Content-Language: pt-BR\r\n".getBytes());

            if (requestStop) {
                return;
            }

            boolean bytes = Recados.getInstance().getConfig().isBytes();

            if (dados.getTipo() == HttpData.NORMAL) {
                byte[] enviar = dados.getUrlFormDataBytes();

                out.write(("Content-Type: application/x-www-form-urlencoded\r\n").getBytes());
                out.write(("Content-Length: " + enviar.length + "\r\n").getBytes());
                out.write("\r\n".getBytes());

                for (int i = 0; i < enviar.length; i++) {
                    out.write(enviar[i]);
                    mensagem = "Enviando: " + i + "/" + enviar.length;
                    out.flush();

                    if (requestStop) {
                        return;
                    }
                }
            } else {
                out.write(("Content-Type: multipart/form-data; boundary=" + dados.getBoundary() + "\r\n").getBytes());
                out.write("\r\n".getBytes());
                out.write(dados.getMultipatFormDataBytes());

                if (requestStop) {
                    return;
                }
                FileConnection fconn = (FileConnection) Connector.open(dados.getUrlArquivo());
                int tamanho = (int) fconn.fileSize();
                DataInputStream arquivo = fconn.openDataInputStream();

                byte[] buf = new byte[1024];
                int enviado = 0;
                tamanho = (bytes ? tamanho : tamanho / 1024);

                for (int read = 0; read != -1; read = arquivo.read(buf)) {
                    out.write(buf, 0, read);
                    out.flush();

                    enviado += read;
                    mensagem = (bytes ? enviado : enviado / 1024) + "/" + tamanho;

                    if (requestStop) {
                        return;
                    }
                }

                out.write(dados.getEndBoundary().getBytes());

                if (requestStop) {
                    return;
                }
            }

            out.write("\r\n\r\n".getBytes());

            out.flush();
            out.close();

            if (requestStop) {
                return;
            }

            mensagem = "Aguardando";

            String fl = Http.readLine(in);

            String codigo = fl.substring(fl.indexOf(' ') + 1, fl.lastIndexOf(' '));

            String frase = fl.substring(fl.lastIndexOf(' ') + 1);

            if (!codigo.equals("200")) {
                estado = FAILED;
                listener.falhaRequisiçao("Problema na rquisiçao " + frase);
                return;
            }

            String linha;

            while (true) {
                linha = readLine(in);
                if (linha.length() < 1) {
                    break;
                }
            }

            if (requestStop) {
                return;
            }

            listener.requisicaoConcluida(in);

            estado = DONE;
        } catch (IOException ex) {
            if (!requestStop) {
                estado = FAILED;
                listener.falhaRequisiçao("Falha ao conectar-se: " + ex.getMessage());
            }
        } catch (SecurityException ex) {
            if (!requestStop) {
                estado = FAILED;
                listener.falhaRequisiçao("Marque usar http em opções. Falha ao conectar-se: " + ex.getMessage());
            }
        } finally {
            requestStop = true;
            closeAll();
        }
    }

    private void runHTTP() {
        try {
            HttpConnection conn = (HttpConnection) Connector.open("http://antoniodiego.comule.com/recados_app" + dados.getPagina(), Connector.READ_WRITE, dados.getTipo() == HttpData.NORMAL);
            conn_ref = conn;

            conn.setRequestMethod(HttpConnection.POST);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0) Gecko/20100101 Firefox/10.0");
            //conn.setRequestProperty("Connection", "close");

            boolean flush = Recados.getInstance().getConfig().isFlush();
            boolean bytes = Recados.getInstance().getConfig().isBytes();

            conn.setRequestProperty("Content-Language", "pt-BR");

            if (dados.getTipo() == HttpData.NORMAL) {
                conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

                byte[] enviar = dados.getUrlFormDataBytes();

                if (requestStop) {
                    return;
                }

                conn.setRequestProperty("Content-Length", Integer.toString(enviar.length));

                out = conn.openDataOutputStream();

                for (int i = 0; i < enviar.length; i++) {
                    out.write(enviar[i]);
                    mensagem = "Enviando: " + i + "/" + enviar.length;

                    if (flush) {
                        out.flush();
                    }

                    if (requestStop) {
                        return;
                    }
                }
            } else if (dados.getTipo() == HttpData.ARQUIVO) {

                conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + dados.getBoundary());

                if (requestStop) {
                    return;
                }

                FileConnection fconn = (FileConnection) Connector.open(dados.getUrlArquivo());
                int tamanho = (int) fconn.fileSize();
                DataInputStream arquivo = fconn.openDataInputStream();

                out.write(dados.getMultipatFormDataBytes());

                byte[] buf = new byte[1024];
                int enviado = 0;
                tamanho = (bytes ? tamanho : tamanho / 1024);

                for (int read = 0; read != -1; read = arquivo.read(buf)) {
                    out.write(buf, 0, read);

                    enviado += read;
                    mensagem = (bytes ? enviado : enviado / 1024) + "/" + tamanho;

                    if (requestStop) {
                        return;
                    }
                }

                out.write(dados.getEndBoundary().getBytes());

                if (flush) {
                    out.flush();
                }

                if (requestStop) {
                    return;
                }
            }

            mensagem = "Aguardando";

            int response = conn.getResponseCode();

            if (response != HttpConnection.HTTP_OK) {
                estado = FAILED;
                listener.falhaRequisiçao("Problema na requisicao");
                requestStop = true;
                return;
            }

            in = conn.openDataInputStream();

            if (requestStop) {
                return;
            }

            listener.requisicaoConcluida(in);

            estado = DONE;
        } catch (IOException ex) {
            if (!requestStop) {
                estado = FAILED;
                listener.falhaRequisiçao("Falha ao conectar-se: " + ex.getMessage());
            }
        } finally {
            requestStop = true;
            closeAll();
        }
    }

    public void cancela() {
        this.requestStop = true;
        closeAll();
        estado = STOPPED;
        listener.requisicaoCancelada();
    }

    private void closeAll() {
        try {
            if (in != null) {
                in.close();
                in = null;
            }

            if (out != null) {
                out.close();
                out = null;
            }

            if (conn_ref != null) {
                conn_ref.close();
                conn_ref = null;
            }

        } catch (IOException ex) {
            if (Recados.getInstance().getConfig().isErros()) {
                Recados.setCurrent(new Alert("Erro","Problema ao fechar conexao", null, AlertType.ERROR));
            }
        }
    }

    /**
     * ************************************************
     */
    public void run() {
        boolean http = Recados.getInstance().getConfig().isHttp();

        if (http) {
            runHTTP();
        } else {
            runSocket();
        }

        estado = WORKING;
    }

    public void doPost(boolean background) {
        this.requestStop = false;

        if (!background) {
            new Timer().scheduleAtFixedRate(new TimerTask() {

                public void run() {
                    if (!requestStop) {
                        repaint();
                    } else {
                        cancel();
                    }
                }
            }, 1000, 500);
        }

        new Thread(this).start();
    }

    public int getEstado() {
        return estado;
    }

    public void setEstado(int estado) {
        this.estado = estado;
    }

    public void setHttpData(HttpData dados) {
        this.dados = dados;
    }

    public HttpData getHttpData() {
        return dados;
    }

    public void setListener(HttpListener listener) {
        this.listener = listener;
    }

    //***********Util*********//
    public static String readLine(DataInputStream in) {
        ByteArrayOutputStream bytes_linha = new ByteArrayOutputStream();

        while (true) {
            try {
                int c = in.read();

                if (c == -1 || (char) c == '\n') {
                    break;
                }

                if ((char) c != '\r') {
                    bytes_linha.write(c);
                }

            } catch (IOException ex) {
                return "";
            }
        }

        try {
            return new String(bytes_linha.toByteArray(), "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            return new String(bytes_linha.toByteArray());
        }
    }
}
